package com.tao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tao.blog.api.BlogServiceApi;
import com.tao.blog.api.pojo.BlogInfoResponse;
import com.tao.common.exception.BlogException;
import com.tao.common.pojo.Result;
import com.tao.common.utils.*;
import com.tao.convert.BeanConvert;
import com.tao.dataobject.EmailUserInfo;
import com.tao.dataobject.UserInfo;
import com.tao.mapper.UserInfoMapper;
import com.tao.service.UserService;
import com.tao.user.api.pojo.UserInfoRegisterRequest;
import com.tao.user.api.pojo.UserInfoRequest;
import com.tao.user.api.pojo.UserInfoResponse;
import com.tao.user.api.pojo.UserLoginResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private BlogServiceApi blogServiceApi;
    @Autowired
    RedisUtils redisUtils;
    @Autowired
    RabbitTemplate rabbitTemplate;

    // 过期时间, 一周
    private static final long EXPIRED_TIME = 7 * 24 * 60 * 60;
    private static final String USER_PREFIX = "user";

    @Override
    public UserLoginResponse login(UserInfoRequest user) {
        log.info("开始登录");
        //验证账号密码是否正确
        UserInfo userInfo = queryUserInfo(user.getUserName());
        if (userInfo==null || userInfo.getId()==null){
            throw new BlogException("用户不存在");
        }

        if (!SecurityUtil.verify(user.getPassword(),userInfo.getPassword())){
            throw new BlogException("用户密码不正确");
        }

        //账号密码正确的逻辑
        Map<String,Object> claims = new HashMap<>();
        claims.put("id", userInfo.getId());
        claims.put("name", userInfo.getUserName());
        String jwt = JWTUtils.genJwt(claims);
        return new UserLoginResponse(userInfo.getId(), jwt);
    }

    private UserInfo queryUserInfo(String userName) {
        // 判断redis存在不存在
        boolean exists = redisUtils.hasKey(userName);
        if(exists) {
            log.info("查询redis");
            // 存在查询redis
            String jsonString = redisUtils.get(userName);
            UserInfo userInfo = JsonUtil.parseObject(jsonString, UserInfo.class);
            return userInfo == null ? selectUserInfoByName(userName) : userInfo;
        }else {
            log.info("查询mysql");
            // 不存在查询mysql
            UserInfo userInfo = selectUserInfoByName(userName);
            if(userInfo != null) {
                // 插入到redis中
                redisUtils.set(redisUtils.buildKey(buildKey(userInfo.getUserName())), JsonUtil.toJson(userInfo), EXPIRED_TIME);
                return userInfo;
            }
        }
        // 没有返回null
        return null;
    }

    @Override
    public UserInfoResponse getUserInfo(Integer userId) {
        UserInfoResponse userInfoResponse = new UserInfoResponse();
        UserInfo userInfo = selectUserInfoById(userId);
        BeanUtils.copyProperties(userInfo, userInfoResponse);
        return userInfoResponse;
    }

    @Override
    public UserInfoResponse selectAuthorInfoByBlogId(Integer blogId) {
        UserInfoResponse userInfoResponse = new UserInfoResponse();
        /**
         * 通过远程调用, 根据博客 id 获取用户id
         */
        //1. 根据博客ID, 获取作者ID
        Result<BlogInfoResponse> blogDeatail = blogServiceApi.getBlogDeatail(blogId);
        //2. 根据作者ID, 获取作者信息
        if (blogDeatail == null || blogDeatail.getData() == null){
            throw new BlogException("博客不存在");
        }

        UserInfo userInfo = selectUserInfoById(blogDeatail.getData().getUserId());

        BeanUtils.copyProperties(userInfo, userInfoResponse);
        return userInfoResponse;
    }

    @Override
    public Integer register(UserInfoRegisterRequest registerRequest) {
        // 校验
        checkUserInfo(registerRequest);
        // 将 UserInfoRegisterRequest 转换成 UserInfo, 插入到数据库中
        UserInfo userInfo = BeanConvert.convertUserInfoByEncrypt(registerRequest);

        try {
            int result = userInfoMapper.insert(userInfo);
            if(result == 1) {
                log.info("注册成功: {}", userInfo);
                // 将数据存储到Redis中, 方便后续使用
                // 此处不进行异常处理, 如果存redis 出现异常, 就不理了, 下次访问数据库的时候再存储
                redisUtils.set(buildKey(userInfo.getUserName()), JsonUtil.toJson(userInfo),  EXPIRED_TIME);
                log.info("插入redis成功: " + userInfo);
                // 发送邮件通知注册成功
                rabbitTemplate.convertAndSend("userExchange", "successful.registration", JsonUtil.toJson(convertToEmailUserInfo(userInfo)));
                return userInfo.getId();
            }else {
                throw new BlogException("注册失败, 请联系管理员");
            }
        }catch (Exception e) {
            log.error("注册失败 error: {}", e);
            throw new BlogException("注册失败, 请联系管理员");
        }

    }

    /**
     * 将userInfo对象 转换成 EmailUserInfo, 用于邮件通知注册成功
     * @param userInfo
     * @return
     */

    private EmailUserInfo convertToEmailUserInfo(UserInfo userInfo) {
        EmailUserInfo emailUserInfo = new EmailUserInfo();
        emailUserInfo.setUserName(userInfo.getUserName());
        emailUserInfo.setEmail(userInfo.getEmail());
        return emailUserInfo;
    }

    private String buildKey(String userName) {
        String key = redisUtils.buildKey(USER_PREFIX, userName);
        return key;
    }


    private void checkUserInfo(UserInfoRegisterRequest registerRequest) {

        // 校验用户名是否存在
        UserInfo result = selectUserInfoByName(registerRequest.getUserName());
        if (result != null) {
            // 用户名已存在, 注册失败
            throw new BlogException("注册失败, 用户名已存在");
        }
        // 校验邮箱, github地址,
        // TODO
        if(!RegexUtil.checkMail(registerRequest.getEmail())) {
            throw new BlogException("注册失败, 邮箱不合法");
        }
        if(!RegexUtil.checkURL(registerRequest.getGithubUrl())) {
            throw new BlogException("注册失败, URL 地址不合法");
        }
    }

    public UserInfo selectUserInfoByName(String userName) {
        return userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getUserName, userName).eq(UserInfo::getDeleteFlag, 0));
    }
    private UserInfo selectUserInfoById(Integer userId) {
        return userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getId, userId).eq(UserInfo::getDeleteFlag, 0));
    }
}
